﻿using Oracle.DataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using WorkFlow.DBProxy;
using WorkFlow.Engine.NSPermission;
using WorkFlow.Engine.NSProcess;

namespace WorkFlow.Engine.NSActivity
{
    public class WfActivity : IEquatable<WfActivity>
    {
        #region 字段

        private readonly WfActivityController _controller;

        public bool IsCreated { get; private set; }

        public int TargetModule { get; private set; }

        public int ID { get; set; } //活动id

        public int IsLocked { get; set; } //是否被锁定

        public DateTime LastVisitedDateTime { get; set; } //最后一次访问时间--和清理内存活动有关

        public int LockOwner { get; set; } //是否被锁定

        public int MainType { get; set; } //活动主类型

        public int NeeOutput { get; set; } //是否需要输出

        public int ProcessId { get; set; } //实例流程id

        public int ProcessVersion { get; set; } //流程版本

        public int Status { get; set; } //活动状态

        public int SubType { get; set; } //活动子类型

        public int RuleActID { get; set; } //规则活动id

        public bool IsSpecifiedUser { get; private set; }

        #region

        /*
         授权用户列表
         */

        public List<WfActAccessorStruct> PrivilegeRules { get; private set; }

        #endregion 字段

        //是否授权用户是指定给运行库活动的

        #endregion 字段

        public WfActivity()
        {
        }

        /// <summary>
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        public WfActivity(int actID, int userID)
        {
            /*
             创建活动
             */
            DataTable dt = null;
            try
            {
                OracleParameter[] obj =
                {
                    new OracleParameter("actid", OracleDbType.Int32) {Value = actID}, //0
                    new OracleParameter("needOutput", OracleDbType.Int32, ParameterDirection.Output), //1
                    new OracleParameter("ruleId", OracleDbType.Int32, ParameterDirection.Output), //2
                    new OracleParameter("processid", OracleDbType.Int32, ParameterDirection.Output), //3
                    new OracleParameter("status", OracleDbType.Int32, ParameterDirection.Output), //4
                    new OracleParameter("maintype", OracleDbType.Int32, ParameterDirection.Output), //5
                    new OracleParameter("asubtype", OracleDbType.Int32, ParameterDirection.Output) //6
                };
                DB.ExecuteProc("GetActivity", obj);
                ID = actID;

                Status = int.Parse(obj[4].Value.ToString());
                RuleActID = int.Parse(obj[2].Value.ToString());
                ProcessId = int.Parse(obj[3].Value.ToString());

                ProcessVersion =
                    Convert.ToInt32(
                        DB.GetFirstField(
                            string.Format(
                                @" select f_version from tr_processes   where f_id =(select F_R_PROCESS_ID from t_processes where f_id={0})",
                                ProcessId)));
                NeeOutput = obj[1] == null
                    ? WfFieldCode.DbFalse
                    : int.Parse(obj[1].Value.ToString());
                MainType = int.Parse(obj[5].Value.ToString());
                try
                {
                    SubType = int.Parse(obj[6].Value.ToString());
                }
                catch
                {
                    SubType = -1;
                }

                //如果为结束活动 结束该活动 同时设置流程
                if (MainType == WfFieldCode.DbMainTyeFinish)
                {
                    WfProcess.Complete(this.ProcessId, true);
                    return;
                }

                //当活动不为路由活动时才执行里面
                if (MainType != WfFieldCode.DbMainRouteType)
                {
                    //-------------------先检查具体活动是否被指定了权限用户 如果指定了 则不需要在查询规则库活动了\
                    IsSpecifiedUser = false;

                    dt =
                        DB.MapToDataTable(
                            string.Format(@"select u.f_id AS PARID,V.F_ID, u.F_MODULE_ID,v.F_ORG_ID,v.F_ROLE_ID,v.F_USER_ID
 from t_act_privileges v,tr_act_user u where v.f_derivedfrom_id=u.f_id and v.f_run_act_id={0}", ID));

                    if (dt == null || dt.Rows.Count < 1)
                    {
                        //----------如果没对具体指定,则查询规则库
                        dt = DB.MapToDataTable(string.Format(
                            @"select F_ID,F_ORG_ID,F_ROLE_ID,F_USER_ID,F_MODULE_ID , 0 AS PARID from tr_act_user where f_act_id={0} ",
                            RuleActID));
                        if (dt == null || dt.Rows.Count < 1)
                        {
                            IsCreated = false;
                            return;
                        }
                        IsSpecifiedUser = false;
                    }
                    else
                    {
                        IsSpecifiedUser = true;
                    }

                    int targetModule = TargetModule;
                    if (!int.TryParse(dt.Rows[0]["F_MODULE_ID"].ToString(), out targetModule))
                    {
                        TargetModule = -1;
                    }
                    else
                    {
                        TargetModule = targetModule;
                    }

                    PrivilegeRules = new List<WfActAccessorStruct>();
                    foreach (DataRow dr in dt.Rows)
                    {
                        PrivilegeRules.Add(new WfActAccessorStruct
                        {
                            _id = Convert.ToInt32(dr["F_ID"].ToString()),
                            _orgID = Convert.ToInt32(dr["F_ORG_ID"].ToString()),
                            _roleID = Convert.ToInt32(dr["F_ROLE_ID"].ToString()),
                            _userID = Convert.ToInt32(dr["F_USER_ID"].ToString()),
                            _ancestorID = Convert.ToInt32(dr["PARID"].ToString())
                        });
                    }
                }
                LockOwner = userID; //userID用来锁定活动
                IsLocked = userID == WfFieldCode.DbNone ? WfFieldCode.DbFalse : WfFieldCode.DbTrue;
                LastVisitedDateTime = DateTime.Now;
                _controller = WfActivityController.CreateActivityController();
                IsCreated = true;//也就是说创建失败的话将不被添加到_controller中.
                _controller.Add(this);
            }
            catch
            {
                IsCreated = false;
            }
            finally
            {
                if (dt != null) dt.Dispose();
            }
        }

        /// <summary>
        /// 两个活动事件相等与否由活动ID和
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(WfActivity other)
        {
            return ID == other.ID && LockOwner == other.LockOwner;
        }

        #region 更改活动状态

        public bool Cancel()
        {
            return _controller.Cancel(this);
        }

        public bool Complete(int outputValue = -1)
        {
            return _controller.Complete(this, outputValue);
        }

        public bool CompleteWithSetNextRunActsPrivilege(WfActAccessorStruct accessor, int nextActID,
            int outputValue = -1)
        {
            return _controller.CompleteWithSetNextRunActsPrivilege(accessor, this, nextActID, outputValue);
        }

        public bool Ready(int activatorID)
        {
            return _controller.Ready(this, activatorID);
        }

        public bool Resume()
        {
            return _controller.Resume(this);
        }

        public bool RollBack()
        {
            return _controller.RollBack(this);
        }

        public bool RollBack(int actID, int userID)
        {
            return _controller.RollBack(actID, userID);
        }

        public bool Run()
        {
            return _controller.Run(this);
        }

        public bool Suspend()
        {
            return _controller.Suspend(this);
        }

        public bool Terminate()
        {
            return _controller.Terminate(this);
        }

        #endregion 更改活动状态

        /// <summary>
        /// 指定用户是否有启动该活动的权限
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool IsUserHasPrivilege(int userID)
        {
            if (!IsCreated) return false;
            WfPermissionController permissionController = WfPermissionController.CreatePermissionController();

            if (MainType != WfFieldCode.DbMainCommonType) return true;

            int count = PrivilegeRules == null ? 0 : PrivilegeRules.Count;
            //先检查是否对运行库活动指定了授权用户
            for (int i = 0; i < count; i++)
            {
                if (PrivilegeRules[i]._userID == userID) return true;
                if (PrivilegeRules[i]._userID + userID == 0) return false;
            }

            //如果用户不成功 在检查组织和角色
            for (int i = 0; i < count; i++)
            {
                if (permissionController.IsUserHasPrivilege(PrivilegeRules[i]._orgID, PrivilegeRules[i]._roleID, userID))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 获取具体的组织
        /// </summary>
        /// <returns></returns>
        public List<WfOrgStruct> GetSpecificOrgs()
        {
            int count = PrivilegeRules == null ? 0 : PrivilegeRules.Count;
            WfPermissionController per = WfPermissionController.CreatePermissionController();
            if (count == 0) return null;
            var list = new List<WfOrgStruct>();
            for (int i = 0; i < count; i++)
            {
                WfOrganization org = per.GetOrgaization(PrivilegeRules[i]._orgID);
                if (org == null || !org.IsCreated) return null;
                //如果组织为抽象类型
                if (org.IsAbstractOrg == WfFieldCode.DbTrue)
                {
                    //如果是抽象单位  那该单位实例洗必然有具体单位的列表 也就是 _specificOrgsCollection
                    int rows = org._specificOrgsCollection == null ? 0 : org._specificOrgsCollection.Count;
                    for (int r = 0; r < rows; r++)
                    {
                        if (!list.Contains(org._specificOrgsCollection[r]))
                        {
                            WfOrgStruct st = org._specificOrgsCollection[r];
                            st._runActID = ID;
                            st._privilegeRuleID = PrivilegeRules[i]._id;
                            list.Add(st);
                        }
                    }
                } // end if abstract type
                else
                {
                    //否则为具体类型
                    var o = new WfOrgStruct
                    {
                        _id = org.ID,
                        _name = org.Name,
                        _abstractID = org.AbstractOrg,
                        _runActID = ID,
                        _privilegeRuleID = PrivilegeRules[i]._ancestorID
                    };
                    //检查是否已经存在该组织了 _id相同认为已经存在
                    if (!IsExists(org.ID, list)) list.Add(o);
                }
            }
            return list;
        }

        private static bool IsExists(int orgID, IReadOnlyList<WfOrgStruct> list)
        {
            int count = list == null ? 0 : list.Count;
            if (count == 0) return false;
            for (int i = 0; i < count; i++)
            {
                // ReSharper disable once PossibleNullReferenceException
                if (list[i]._id == orgID) return true;
            }
            return false;
        }
    }
}